package fivecardstudd;

import java.util.ArrayList;

public class Hand  {
        private ArrayList<Card> hand;
        int cardCount;
        int[] ranking;
        
        
        public Hand() {
                hand = new ArrayList<Card>();
                cardCount = 0;
                ranking = new int[6];
        }
        
      
        public ArrayList<Card> getHand() {
                return hand;
        }

        public int getCardCount() {
                return cardCount;
        }
        
       
        public void addCard(Card card){
                hand.add(card);
                cardCount++;
        }
        
        
        public void reset(){
                hand.clear();
                cardCount = 0;
        }
        
       
        public void setFaceUp(){
                for(Card card: hand){
                        if(!card.isFaceUp())
                                card.setFaceUp(true);
                }
        }
        
       
        private void swap(int i, int j){
                Card temp;
                temp = hand.get(i); 
                hand.set(i, hand.get(j));
                hand.set(j, temp);
        }
       
        public ArrayList<Card> sortHand(ArrayList<Card> hand){
                ArrayList<Card> sortedHand = new ArrayList<Card>();
                
                //copy the contents of hand into sorted hand
                for(Card card: hand){
                        Card toAdd = new Card(card.getRank(), card.getSuit());
                        sortedHand.add(toAdd);
                }
                
                //use insertion sort to order the cards
                for(int i=1; i<sortedHand.size(); i++){
                        for(int j=i; j>0 && sortedHand.get(j).getCardValue()>
                                        sortedHand.get(j-1).getCardValue(); j--){
                                swap(j, j-1);
                        }
                }
                
                return sortedHand;
        }
        
     
        public int[] determineHandRanking(){
                if(isRoyalFlush(hand))
                        return ranking;
                else if (isStraightFlush(hand))
                        return ranking;
                else if (isFourOfAKind(hand))
                        return ranking;
                else if (isFullHouse(hand))
                        return ranking;
                else if (isFlush(hand))
                        return ranking;
                else if (isStraight(hand))
                        return ranking;
                else if (isThreeOfAKind(hand))
                        return ranking;
                else if (isTwoPair(hand))
                        return ranking;
                else if (isPair(hand))
                        return ranking;
                else{
                        highCard(hand);
                        return ranking;
                }
        }
        
       
        public int[] determineVisibleHandRanking(){
                //create a list of only the faceUp cards in the current hand
                ArrayList<Card> visibleHand = this.visibleHand();
                
                //if the hand has less than 3 visible cards, test for Pair and High Card
                if(visibleHand.size() < 3){
                        if (isPair(visibleHand))
                                return ranking;
                        else{
                                highCard(visibleHand);
                                return ranking;
                        }
                } 
                //if the hand has 3 visible cards, test for 3 of a kind, Pair and High Card
                else if(visibleHand.size() == 3){
                        if (isThreeOfAKind(visibleHand))
                                return ranking;
                        else if (isPair(visibleHand))
                                return ranking;
                        else{
                                highCard(visibleHand);
                                return ranking;
                        }
                }
                
                /* if the hand has 4 visible cards, test for 4 of a kind, 
                 * 3 of a kind, 2 pair, Pair and High Card
                 */
                else if(visibleHand.size() == 4){
                        if (isFourOfAKind(visibleHand))
                                return ranking;
                        else if (isThreeOfAKind(visibleHand))
                                return ranking;
                        else if (isTwoPair(visibleHand))
                                return ranking;
                        else if (isPair(visibleHand))
                                return ranking;
                        else{
                                highCard(visibleHand);
                                return ranking;
                        }
                }

                
                return ranking;
        }
        
      
        public ArrayList<Card> visibleHand(){
                ArrayList<Card> visibleHand = new ArrayList<Card>();
             
                for(Card card: hand){
                        Card upCard = new Card(card.getRank(), card.getSuit());
                        if(card.isFaceUp()){
                                visibleHand.add(upCard);
                        }
                }
                
                return visibleHand;
        }
        
      
        public boolean isRoyalFlush(ArrayList<Card> hand){
             
                ArrayList<Card> sorted = sortHand(hand);
                
                if(!isFlush(sorted) || !isStraight(sorted)){
                        return false;
                }
              
                else{
                        if(sorted.get(sorted.size()-1).getCardValue() == 10){
                                
                                ranking[0] = 10;
                                return true;
                        }
                        else 
                                return false;
                }
        }
        
      
        public boolean isStraightFlush(ArrayList<Card> hand){
              
                ArrayList<Card> sorted = sortHand(hand);
                
                if(!isStraight(sorted) || !isFlush(sorted))
                        return false;
            
                else{
               
                        ranking[0] = 9;
                      
                        for(int i=0; i<sorted.size(); i++){
                                ranking[i+1] = sorted.get(i).getCardValue();
                        }
                        return true;
                }
        }
        
       
        public boolean isFourOfAKind(ArrayList<Card> hand){
            
                ArrayList<Card> sorted = sortHand(hand);
                
                int count = 1; //to be used to count number of repeated cards           
                int pastValue = sorted.get(0).getCardValue();
                int currentValue;
                
                for(int i = 1; i<sorted.size(); i++){
                      
                        currentValue = sorted.get(i).getCardValue();
                        if(currentValue == pastValue)
                                count++;
                        else
                                count = 1;
                        if(count == 4){
                                ranking[0] = 8;
                                ranking[1] = currentValue;
                                for(Card card: sorted){
                                        if(card.getCardValue() != currentValue)
                                                ranking[2] = card.getCardValue();
                                }
                                
                                return true;
                        }
                        pastValue = currentValue;
                }
               
                return false;
        }
        
      
        public boolean isFullHouse(ArrayList<Card> hand){
               
                ArrayList<Card> sorted = sortHand(hand);
                
                int count = 1;
                int totalCount = 0;
                int pastValue = sorted.get(0).getCardValue();
                int currentValue;
              
                for(int i = 1; i<sorted.size(); i++){
                  
                        currentValue = sorted.get(i).getCardValue();
                        if(currentValue == pastValue)
                                count++;
                        else
                                count = 1;
                         if(count == 3){
                                
                                totalCount += count; 
                                count = 1;
                                ranking[1] = currentValue;
                        }
                        pastValue = currentValue;
                }
          
                for(int i = 1; i<sorted.size(); i++){
                       
                        currentValue = sorted.get(i).getCardValue();
                       if(currentValue == pastValue && currentValue != ranking[1])
                                count++;
                        else
                                count = 1;
                        if(count == 2){
                          
                                totalCount += count; 
                                count = 1;
                                ranking[2] = currentValue;
                        }
                        pastValue = currentValue;
                }
      
                if(totalCount == 5){
                       
                        ranking[0] = 7;
                        return true;
                }

                else{
                        return false;
                }
        }
        
      
        public boolean isFlush(ArrayList<Card> hand){
                
                ArrayList<Card> sorted = sortHand(hand);
                Card.CardSuitEnum suit = sorted.get(0).getSuit();
           
                for(int i=1; i<sorted.size(); i++){
                        if(sorted.get(i).getSuit() != suit)
                                return false;
                }
                  ranking[0] = 6;
           
                for(int i=0; i<sorted.size(); i++){
                        ranking[i+1] = sorted.get(i).getCardValue();
                }
                return true;
                
        }
        
       
        public boolean isStraight(ArrayList<Card> hand){
              
                ArrayList<Card> sorted = sortHand(hand);
                  if(this.containsAce()){
                        //ace will count as 1 if the next highest card is a FIVE
                        if(sorted.get(1).getCardValue() == 5){
                             for(int i=2; i<sorted.size(); i++){
                                       if(sorted.get(i-1).getCardValue() != 
                                                        sorted.get(i).getCardValue() + 1){
                                                return false;
                                        }
                                }
                               
                                ranking = new int[]{5, 5, 4, 3, 2, 1};
                                return true;
                        }
                        
                        else if(sorted.get(1).getCardValue() == 13){

                                for(int i=1; i<sorted.size(); i++){
                                  
                                        if(sorted.get(i-1).getCardValue() != 
                                                        sorted.get(i).getCardValue() + 1){
                                                return false;
                                        }
                                }
                           
                                ranking = new int[]{5, 14, 13, 12, 11, 10};
                                return true;
                        }
                        else
                                return false;
                }
            
                else{
                          for(int i=1; i<sorted.size(); i++){
                               
                                if(sorted.get(i-1).getCardValue() != 
                                                sorted.get(i).getCardValue() + 1){
                                        return false;
                                }
                        }
                     
                        ranking[0] = 5;
                     
                        for(int i=0; i<sorted.size(); i++){
                                ranking[i+1] = sorted.get(i).getCardValue();
                        }
                        
                        return true;
                }

        }
     
        private boolean containsAce(){
            for(Card card: hand){
                        if(card.getCardValue() == 14)
                                return true;
                }
             return false;
        }
        
       
        public boolean isThreeOfAKind(ArrayList<Card> hand){
              
                ArrayList<Card> sorted = sortHand(hand);
                
                int count = 1;         
                int pastValue = sorted.get(0).getCardValue();
                int currentValue;
                
                for(int i = 1; i<sorted.size(); i++){
                       
                        currentValue = sorted.get(i).getCardValue();
                     
                        if(currentValue == pastValue)
                                count++;
                         else
                                count = 1;
                        
                        if(count == 3){
                                ranking[0] = 4;
                                ranking[1] = currentValue;
                             
                                int k = 2; 
                                for(Card card: sorted){ 
                                        if(card.getCardValue() != currentValue){
                                                ranking[k] = card.getCardValue();
                                                k++;
                                        }
                                }
                                return true;
                        }
                        pastValue = currentValue;
                }
                
                return false;
        }
        
      
        public boolean isTwoPair(ArrayList<Card> hand){
               
                ArrayList<Card> sorted = sortHand(hand);
                
                int count = 1;
                int totalCount = 0;
                int pastValue = sorted.get(0).getCardValue();
                int currentValue;
                
                for(int i = 1; i<sorted.size(); i++){
                        
                        currentValue = sorted.get(i).getCardValue();
                      
                        if(currentValue == pastValue)
                                count++;
                        else
                                count = 1;
                          if(count == 2){
                                    totalCount += count; 
                                    count = 1;
                               if(totalCount == 2){
                                      ranking[1] = currentValue;
                                }
                               if(totalCount == 4){
                                         ranking[0] = 3;
                                         ranking[2] = currentValue;
                                        
                                        for(Card card: sorted){ 
                                                if(card.getCardValue() != currentValue && 
                                                                card.getCardValue() != ranking[1]){
                                                        ranking[3] = card.getCardValue();
                                                }
                                        }
                                        return true;
                                }
                        }
                        pastValue = currentValue;
                }
               return false;
        }
        
      
        public boolean isPair(ArrayList<Card> hand){
               
                ArrayList<Card> sorted = sortHand(hand);
                
                int count = 1; //to be used to count number of repeated cards           
                int pastValue = sorted.get(0).getCardValue();
                int currentValue;
                
                for(int i = 1; i<sorted.size(); i++){
                        
                        currentValue = sorted.get(i).getCardValue();
                        
                        if(currentValue == pastValue)
                                count++;
                         else
                                count = 1;
                      
                        if(count == 2){
                                //set the first element of the ranking array to 2
                                ranking[0] = 2;
                                ranking[1] = currentValue;
                          
                                int k = 2; //will be used in for loop to assign index 2, 3 and 4
                                for(Card card: sorted){ 
                                        if(card.getCardValue() != currentValue){
                                                ranking[k] = card.getCardValue();
                                                k++;
                                        }
                                }
                                return true;
                        }
                        pastValue = currentValue;
                }
                
                return false;
        }
      
        public void highCard(ArrayList<Card> hand){
             
                ArrayList<Card> sorted = sortHand(hand);
                ranking[0] = 1;
             
                for(int i=0; i<sorted.size(); i++){
                        ranking[i+1] = sorted.get(i).getCardValue();
                }
        }
        
        @Override
        public String toString(){
                String handString = "";
                for(Card card: hand){
                        if(!card.isFaceUp()){
                                handString += "(D)";
                        }
                        handString += ""+card.getCardValue()+" of "+card.getSuit()+" \t";
                }
                
                return handString;
        }
        
       
        public String rankingString(){
                String rankString = "";
                int rank = ranking[0];
                
                switch(rank){
                        case 1: rankString += "High Card "+ranking[1];
                                break;
                        
                        case 2: rankString += "Pair of "+ranking[1]+"s";
                                break;
                                
                        case 3: rankString += "Two Pair "+ranking[1]+" & "+ranking[2];
                                break;
                                
                        case 4: rankString += "Three of a Kind "+ranking[1];
                                break;
                                
                        case 5: rankString += "Straight (highest card is "+ranking[1]+")";
                                break;
                                
                        case 6: rankString += "Flush (highest card is "+ranking[1]+")";
                                break;
                                
                        case 7: rankString += "Full House (triple of "+ranking[1]+", pair of "+ranking[2]+")";
                                break;
                                
                        case 8: rankString += "Four of a Kind "+ranking[1];
                                break;
                        
                        case 9: rankString += "Straight Flush (highest card is "+ranking[1]+")";
                                break;
                                
                        case 10: rankString += "ROYAL FLUSH!!!";
                                break;
                }
                
                return rankString;
        }
}

